﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using QLabValues;
using AtomicTypes;






namespace NumericalCalculations
{
    public partial class Functions
    {


        public List<IQLabValue> vertcat(List<IQLabValue> o)
        {




            if (o.Count == 0)
            {
                throw (new NumericalCalculationsException("??? Too little arguments for function vertcat\n"));
            }
            else if (o.Count == 1) return o;
            else if (o.Count == 2)
            {
                // Ako su oba konstante ne interesuje me moze i da se obrise ovaj deo koda posle
                /*
#region Jedna,Dve const
                if (Helper.checkIfCellIsScalar(o[0]) && Helper.checkIfCellIsScalar(o[1]))
                {
                    //Pravim matricu reda [1,2] i to vracam
                    int[] niz= {2,1};
                    QFloat64NDimArray pom=new QFloat64NDimArray(niz);
                    //Treba postaviti vrednosti 
                }
                else if ( (Helper.checkIfCellIsScalar(o[0]) && !(Helper.checkIfCellIsScalar(o[1])) || ( !(Helper.checkIfCellIsScalar(o[0])) && Helper.checkIfCellIsScalar(o[1])) ))
                //Ako je jedan konstanta a drugi nije
                {
                    
                        throw (new NumericalCalculationsException("??? Numerical types not consistent\n");
                }
#endregion
                 */
                //Ako su je prvi QCharNdimArray a drugi moze da se konvertuje - tu je ukljuceno i da je string - treba jos dorada
                #region Prvi QCharNDimArray a drugi moze da se konvertuje ili obrnuto
                if (((o.ElementAt(0).GetEnumType() == IQLabValueType.QCharNDimArray) && Helper.canConvertToEnum(o.ElementAt(1), IQLabValueType.QCharNDimArray)) || ((o.ElementAt(1).GetEnumType() == IQLabValueType.QCharNDimArray) && Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCharNDimArray)))
                {
                    //pretvaram sve u of - listu ndimenzionih nizova karaktera 
                    List<QCharNDimArray> of = new List<QCharNDimArray>();
                    foreach (var oel in o)
                        of.Add(new QCharNDimArray(oel));

                    //Vadimo dimenzije
                    int[] fd = (int[])((QCharNDimArray)of.ElementAt(0)).DimensionSize.Clone();
                    int[] sd = (int[])((QCharNDimArray)of.ElementAt(1)).DimensionSize.Clone();

                    // Pitamo da li ima isti broj dimenzija
                    if (fd.Count() != sd.Count())
                    {
                        throw (new NumericalCalculationsException("??? Dimensions\n"));
                    }
                    //Zatim da li se dimenzije poklapaju
                    for (int i = 1; i < fd.Count(); i++)
                        if (fd[i] != sd[i])
                            throw (new NumericalCalculationsException("??? Dimensions\n"));
                    //Dodajem nultu dimenziju na drugu posto mi prva treba netaknuta 
                    sd[0] += fd[0];
                    // pravim pomocnu ndimenzioni niz karaktera dimenzija sd
                    QCharNDimArray pom = new QCharNDimArray(sd);

                    Counter c = new Counter(pom.DimensionSize);

                    for (c.reset(); !c.isAtEnd(); c.plusPlus())
                    {
                        int[] index = c.getCurrent();
                        if (fd[0] >= index[0]) pom[index] = (of.ElementAt(0))[index];
                        else
                        {
                            int[] pom1 = (int[])index.Clone();
                            pom1[0] = index[0] - fd[0];
                            pom[index] = (of.ElementAt(1))[pom1];
                        }

                    }
                    List<IQLabValue> rez = new List<IQLabValue>();
                    rez.Add(pom);
                    return rez;


                }
                #endregion
                //ako je jedan od dva QCharNDimArray a drugi ne moze da se konvertuje 
                #region Ako je prvi QCharNDimArray a drugi ne moze da se konvertuje
                else if ((o.ElementAt(0).GetEnumType() == IQLabValueType.QCharNDimArray) && !(Helper.canConvertToEnum(o.ElementAt(1), IQLabValueType.QCharNDimArray)))
                {
                    //Ovde znamo da treba da izbacimo warning i da uradimo dalje
                    //Kada se napravi globalna promenljiva za warninge ovde treba da se doda deo koda
                    if (!(Helper.canConvertToEnum(o.ElementAt(1), IQLabValueType.QFloat64NDimArray)))
                    {
                        throw (new NumericalCalculationsException("??? Undefined function or method 'vertcat' for input arguments of type " +
                        Helper.PrintEnumName(Helper.TypeOfThatCouldNotConvert(o, IQLabValueType.QFloat64NDimArray)) + "."));
                    }

                    int[] fd = (int[])((QCharNDimArray)o.ElementAt(0)).DimensionSize.Clone();
                    int[] sd = (int[])((QFloat64NDimArray)o.ElementAt(1)).DimensionSize.Clone();

                    if (fd.Count() != sd.Count())
                    {
                        throw (new NumericalCalculationsException("??? Dimensions\n"));
                    }
                    //Zatim da li se dimenzije poklapaju
                    for (int i = 1; i < fd.Count(); i++)
                        if (fd[i] != sd[i])
                            throw (new NumericalCalculationsException("??? Dimensions\n"));
                    //Dodajem nultu dimenziju na drugu posto mi prva treba netaknuta 
                    sd[0] += fd[0];
                    QCharNDimArray pom = new QCharNDimArray(sd);
                    //Dalje ce da konvertujemo sve u qfloat64ndimarray
                    QFloat64NDimArray el2 = new QFloat64NDimArray(o.ElementAt(1));
                    Counter c = new Counter(pom.DimensionSize);

                    for (c.reset(); !c.isAtEnd(); c.plusPlus())
                    {
                        int[] index = c.getCurrent();
                        if (fd[0] >= index[0]) pom[index] = ((QCharNDimArray)o.ElementAt(0))[index];
                        else
                        {
                            QChar ch = new QChar(' ');
                            int[] pom1 = (int[])index.Clone();
                            pom1[0] = index[0] - fd[0];
                            QFloat64 br = new QFloat64(((QFloat64NDimArray)o.ElementAt(1))[pom1]);

                            // oko nule proveri koliko mu je int od -0.1 ako je -1 onda je ok ako je 0 onda treba staviti <=-1
                            //Char u matlabu je od 0 do 255 ukljucujuci i granice tj extended ascii
                            if ((br.Real < 0) || (br.Real >= 256))
                            {
                                //Ovde znamo da treba da izbacimo warning i da uradimo dalje
                                //Kada se napravi globalna promenljiva za warninge ovde treba da se doda deo koda
                                pom[index] = ch;
                            }
                            else
                            {
                                //Inace znamo da je karakter
                                QInt64 br2 = new QInt64(br);
                                QChar br3 = new QChar(br2);
                                pom[index] = br3;
                            }


                        }

                    }
                    List<IQLabValue> rez = new List<IQLabValue>();
                    rez.Add(pom);
                    return rez;

                    //Onda cemo da idemo i pitamo da li pojedinacni moze da se pretvori u char ako moze super ako ne izbacujem razmak
                }
                #endregion
                // Ovde isto kao u prethodnom elsu samo je sledeci
                #region Ako je drugi QCharNDimArray a prvi ne moze da se konvertuje
                else if ((o.ElementAt(1).GetEnumType() == IQLabValueType.QCharNDimArray) && !(Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QCharNDimArray)))
                {
                    //Ovde znamo da treba da izbacimo warning i da uradimo dalje
                    //Kada se napravi globalna promenljiva za warninge ovde treba da se doda deo koda
                    if (!(Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QFloat64NDimArray)))
                    {
                        throw (new NumericalCalculationsException("??? Undefined function or method 'vertcat' for input arguments of type " +
                        Helper.PrintEnumName(Helper.TypeOfThatCouldNotConvert(o, IQLabValueType.QFloat64NDimArray)) + "."));
                    }

                    int[] fd = (int[])((QFloat64NDimArray)o.ElementAt(1)).DimensionSize.Clone();
                    int[] sd = (int[])((QCharNDimArray)o.ElementAt(0)).DimensionSize.Clone();

                    if (fd.Count() != sd.Count())
                    {
                        throw (new NumericalCalculationsException("??? Dimensions\n"));
                    }
                    //Zatim da li se dimenzije poklapaju
                    for (int i = 1; i < fd.Count(); i++)
                        if (fd[i] != sd[i])
                            throw (new NumericalCalculationsException("??? Dimensions\n"));
                    //Dodajem nultu dimenziju na drugu posto mi prva treba netaknuta 
                    sd[0] += fd[0];
                    QCharNDimArray pom = new QCharNDimArray(sd);
                    //Dalje ce da konvertujemo sve u qfloat64ndimarray
                    QFloat64NDimArray el2 = new QFloat64NDimArray(o.ElementAt(0));
                    Counter c = new Counter(pom.DimensionSize);

                    for (c.reset(); !c.isAtEnd(); c.plusPlus())
                    {
                        int[] index = c.getCurrent();
                        if (fd[0] >= index[0]) pom[index] = ((QCharNDimArray)o.ElementAt(1))[index];
                        else
                        {
                            QChar ch = new QChar(' ');
                            int[] pom1 = (int[])index.Clone();
                            pom1[0] = index[0] - fd[0];
                            QFloat64 br = new QFloat64(((QFloat64NDimArray)o.ElementAt(0))[pom1]);

                            // oko nule proveri koliko mu je int od -0.1 ako je -1 onda je ok ako je 0 onda treba staviti <=-1
                            //Char u matlabu je od 0 do 255 ukljucujuci i granice tj extended ascii
                            if ((br.Real < 0) || (br.Real >= 256))
                            {
                                //Ovde znamo da treba da izbacimo warning i da uradimo dalje
                                //Kada se napravi globalna promenljiva za warninge ovde treba da se doda deo koda
                                pom[index] = ch;
                            }
                            else
                            {
                                //Inace znamo da je karakter
                                QInt64 br2 = new QInt64(br);
                                QChar br3 = new QChar(br2);
                                pom[index] = br3;
                            }


                        }

                    }
                    List<IQLabValue> rez = new List<IQLabValue>();
                    rez.Add(pom);
                    return rez;

                    //Onda cemo da idemo i pitamo da li pojedinacni moze da se pretvori u char ako moze super ako ne izbacujem razmak

                }
                #endregion
                //Ako oba mogu da se konvertuju u QFloat64NDimArray
                #region INACE ako oba mogu da se konvertuju u QFloat64NDimArray
                else if (Helper.canConvertListToEnum(o, IQLabValueType.QFloat64NDimArray))
                {
                    List<QFloat64NDimArray> of = new List<QFloat64NDimArray>();
                    foreach (var oel in o)
                        of.Add(new QFloat64NDimArray(oel));
                    int[] fd = (int[])((QFloat64NDimArray)o.ElementAt(0)).DimensionSize.Clone();
                    int[] sd = (int[])((QFloat64NDimArray)o.ElementAt(1)).DimensionSize.Clone();

                    if (fd.Count() != sd.Count())
                    {
                        throw (new NumericalCalculationsException("??? Dimensions\n"));
                    }
                    for (int i = 1; i < fd.Count(); i++)
                        if (fd[i] != sd[i])
                            throw (new NumericalCalculationsException("??? Dimensions\n"));
                    sd[0] += fd[0];
                    QFloat64NDimArray pom = new QFloat64NDimArray(sd);
                    Counter c = new Counter(pom.DimensionSize);



                    for (c.reset(); !c.isAtEnd(); c.plusPlus())
                    {
                        int[] index = c.getCurrent();
                        if (fd[0] >= index[0]) pom[index] = (of.ElementAt(0))[index]; // Ovde je pisalo fd[0]<=index[0] sto mislim da nije tacno
                        else
                        {
                            int[] pom1 = (int[])index.Clone();
                            pom1[0] = index[0] - fd[0];
                            pom[index] = (of.ElementAt(1))[pom1];
                        }

                    }
                    List<IQLabValue> rez = new List<IQLabValue>();
                    rez.Add(pom);
                    return rez;


                }
                #endregion
                //Ako ne mozemo da konvertujemo u QFloat64NDimArray
                else
                {
                    throw (new NumericalCalculationsException("??? Undefined function or method 'vertcat' for input arguments of type " +
                   Helper.PrintEnumName(Helper.TypeOfThatCouldNotConvert(o, IQLabValueType.QFloat64NDimArray)) + "."));
                }
            }
            else
            {

                List<IQLabValue> pom = new List<IQLabValue>();
                List<IQLabValue> pom2 = new List<IQLabValue>();
                //pom=vertcat(o[1]);
                // ne moze da se prosledi ostatak liste preko indeksa
                //to mora da se sredi
                pom2[1] = pom[0];
                pom2[0] = o[0];
                return vertcat(pom);
            }

        }

    }
}
//Proveriti sa daretom ili netkom da li se krecem kroz ndimarray onako ili kao u plus fji...